/*
 Trabajo Practico 3 Ejercicio 1
 Segunda Entrega

 - Integrantes:
	- Martinez, Guillermo	DNI: 34510461
	- Barrera, Lourdes		DNI: 33306634
	- Reyes, Leandro		DNI: 34213699
	- Rodriguez, Lucas		DNI: 34265017
*/

#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <stdio.h>
#include <sys/select.h>
#include <unistd.h>
#include <termios.h>

void CreaSemaforos();
void CerrarSemaforos();

int Salir=0;

sem_t *MutexCaja = NULL, *MutexTramiteFinalizado = NULL;
sem_t *HayClientes = NULL, *HayVips = NULL;
sem_t *PasaComunes = NULL,*PasaVips = NULL, *BancoAbierto = NULL;

char _MutexCaja[] = "SMutexCaja";
char _MutexTramiteFinalizado [] = "SMutexTramiteFinalizado";
char _HayClientes [] = "SHayClientes";
char _HayVips [] = "SHayVIps";
char _PasaComunes [] = "SPasaComunes";
char _PasaVips [] = "SPasaVips";
char _BancoAbierto [] = "SBancoAbierto";

// Para terminar servidor
void handler_term(int);

void main(int argc, char *argv[])
{
	int j,val;
	
	// Ignoro señales
	for(j=1;j<32;j++)
		if(j!= 9  && j != 19)
			signal(j, SIG_IGN);
			
	signal(SIGINT,handler_term);
	signal(SIGTERM,handler_term);
  j = 0;
  
	printf("Atención %d > Iniciando... Para finalizar presione CTRL+C \n", getpid());
	CreaSemaforos();

	sem_getvalue(HayClientes, &val);

	while((!Salir) || val != 0)
	{
		if(!sem_trywait(HayClientes))
		{
			if(!sem_trywait(HayVips))
			{
				printf("Atención %d > Atendiendo cliente VIP\n", getpid());
				sem_post(PasaVips);
			}
			
			else
			{
				printf("Atención %d > Atendiendo cliente Comun\n", getpid());
				sem_post(PasaComunes);
			}

			sem_getvalue(HayClientes, &val);

			do
			{
				j = sem_wait(MutexTramiteFinalizado);
			}while(j != 0 && errno != EINTR);
			
			sem_getvalue(HayClientes, &val);
		}
	}
	
	printf("\nBanco cerrado.\n");
	CerrarSemaforos();			
}

void CreaSemaforos()
{
	if((MutexCaja = sem_open(_MutexCaja,O_CREAT | O_EXCL ,0666,1)) == SEM_FAILED)
		goto Error;
		
	if((MutexTramiteFinalizado = sem_open(_MutexTramiteFinalizado,O_CREAT | O_EXCL,0666,0)) == SEM_FAILED) 
		goto Error;
		
	if((HayClientes = sem_open(_HayClientes,O_CREAT | O_EXCL,0666,0)) == SEM_FAILED) 
		goto Error;
		
	if((HayVips = sem_open(_HayVips,O_CREAT | O_EXCL,0666,0)) == SEM_FAILED)
		goto Error;		
	
	if((PasaComunes = sem_open(_PasaComunes,O_CREAT | O_EXCL,0666,0)) == SEM_FAILED)
		goto Error;
		
	if((PasaVips = sem_open(_PasaVips,O_CREAT | O_EXCL,0666,0)) == SEM_FAILED) 
		goto Error;

	if((BancoAbierto = sem_open(_BancoAbierto,O_CREAT | O_EXCL ,0666,1)) == SEM_FAILED)
		goto Error;
		
	return;
	
Error:
	printf("Error al crear semaforos \n");
	CerrarSemaforos();
	exit(-1);
}

void CerrarSemaforos()
{
	if(MutexCaja)
	{
		sem_close(MutexCaja);
		sem_unlink(_MutexCaja);
	}
	
	if(MutexTramiteFinalizado)
	{
		sem_close(MutexTramiteFinalizado);
		sem_unlink(_MutexTramiteFinalizado);
	}
	
	if(HayClientes)
	{
		sem_close(HayClientes);
		sem_unlink(_HayClientes);
	}
	
	if(HayVips)
	{	
		sem_close(HayVips);
		sem_unlink(_HayVips);
	}
	
	if(PasaComunes)
	{	
		sem_close(PasaComunes);
		sem_unlink(_PasaComunes);
	}

	if(BancoAbierto)
	{	
		sem_close(BancoAbierto);
		sem_unlink(_BancoAbierto);
	}

	if(PasaVips)
	{	
		sem_close(PasaVips);
		sem_unlink(_PasaVips);
	}
}

void handler_term(int sig)
{
	int aux = 0;

	signal(SIGINT,SIG_IGN);
	signal(SIGTERM,SIG_IGN);
	sem_getvalue(HayClientes, &aux);
	
	if(aux > 0)
		printf("\nAtiendo a los %d clientes restantes y luego cierro el banco.\n",aux);
		
	Salir = 1;
	sem_wait(BancoAbierto);
}
